#![cfg_attr(not(feature = "std"), no_std)]

/// Edit this file to define custom logic or remove it if it is not needed.
/// Learn more about FRAME and the core library of Substrate FRAME pallets:
/// https://substrate.dev/docs/en/knowledgebase/runtime/frame

use frame_support::{ensure,decl_module, decl_storage, decl_event, decl_error, dispatch, traits::Get};
use frame_system::ensure_signed;
use sp_std::prelude::*;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

/// Configure the pallet by specifying the parameters and types on which it depends.
pub trait Trait: frame_system::Trait {
	/// Because this pallet emits events, it depends on the runtime's definition of an event.
	type Event: From<Event<Self>> + Into<<Self as frame_system::Trait>::Event>;
}

// The pallet's runtime storage items.
// https://substrate.dev/docs/en/knowledgebase/runtime/storage
decl_storage! {
	// A unique name is used to ensure that the pallet's storage items are isolated.
	// This name may be updated, but each pallet in the runtime must use a unique name.
	// ---------------------------------vvvvvvvvvvvvvv
	trait Store for Module<T: Trait> as TemplateModule {
		Proofs get(fn proofs): map hasher(blake2_128_concat) Vec<u8> =>(T::AccountId,T::BlockNumber);
	}
}


// Pallets use events to inform users when important changes are made.
// https://substrate.dev/docs/en/knowledgebase/runtime/events
decl_event!(
	pub enum Event<T> where AccountId = <T as frame_system::Trait>::AccountId,BlockNumber = <T as frame_system::Trait>::BlockNumber {
		//创建
		ClaimCreated(AccountId,Vec<u8>),
		//注销
		ClaimRemove(AccountId,Vec<u8>),
		//转存
		ClaimTransfer(AccountId, AccountId, BlockNumber),
	}
);

// Errors inform users that something went wrong.
decl_error!{
	pub enum Error for Module<T: Trait> {
		ProofAlreadyExist,
		ClaimNotExist,
		NotClaimOwner,
		NotProofOwner,
		NoSuchProof,
	}
}


decl_module! {
	pub struct Module<T: Trait> for enum Call where origin: T::Origin {
		type Error = Error<T>;

		fn deposit_event() = default;

		#[weight=0]
		pub fn create_claim(origin, claim: Vec<u8>)->dispatch::DispatchResult{
			//获取id
			let sender = ensure_signed(origin)?;
			//验证是否存在
			ensure!(!Proofs::<T>::contains_key(&claim),Error::<T>::ProofAlreadyExist);
			//保存
			Proofs::<T>::insert(&claim,(sender.clone(),frame_system::Module::<T>::block_number()));
			//触发事件
			Self::deposit_event(RawEvent::ClaimCreated(sender,claim));
			Ok(())
		}

		#[weight = 0]
		pub fn remove_claim(origin, claim:Vec<u8>)->dispatch::DispatchResult{
			//获取id
			let sender = ensure_signed(origin)?;
			//验证是否存在
			ensure!(!Proofs::<T>::contains_key(&claim),Error::<T>::ClaimNotExist);
			//获取当前key对应的值
			let (owner,_block_number) = Proofs::<T>::get(&claim);
			//判断发送方是否正确
			ensure!(owner == sender,Error::<T>::NotClaimOwner);
			//删除
			Proofs::<T>::remove(&claim);
			//触发事件
			Self::deposit_event(RawEvent::ClaimRemove(sender,claim));

			Ok(())
		}


		  /// 转移存证 , 将某个存证的信息转移到另外一个 AccountId 下
		  #[weight = 0]
		  fn transfer_claim(origin , receiver_address: T::AccountId, proof: Vec<u8> )->dispatch::DispatchResult{
			  let sender = ensure_signed(origin)?;
			  // 1、读取存证信息，主要就是存证的值
			  let (owner, value) = Proofs::<T>::get(&proof);
			  // 2、验证当前的调用者是证声明的所有者，如果不匹配返回 NotProofOwner
			  ensure!(sender == owner, Error::<T>::NotProofOwner);
			  // 3、删除存证。 // 直接调用 revoke_claim(origin, proof); 不会调用
			  // revoke_claim(origin, proof);  // 不会调用
			  // 校验存证签名是否存在
			  ensure!(Proofs::<T>::contains_key(&proof), Error::<T>::NoSuchProof);
			  // 从存储中移除声明
			  Proofs::<T>::remove(&proof);
			  // 4、将存证转移到新地址中
			  Proofs::<T>::insert(&proof, (&receiver_address, value));
			  // 5、发送事件通知：
			  Self::deposit_event(RawEvent::ClaimTransfer(sender, receiver_address,value));
			  Ok(())
		  }


	}
}
